;; This file is part of GNUnet.
;; Copyright (C) 2001, 2002, 2003, 2004, 2009, 2011 GNUnet e.V.
;;
;; GNUnet is free software: you can redistribute it and/or modify it
;; under the terms of the GNU Affero General Public License as published
;; by the Free Software Foundation, either version 3 of the License,
;; or (at your option) any later version.
;;
;; GNUnet is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
;;
;; SPDX-License-Identifier: AGPL-3.0-or-later

(define-library (gnu gnunet dht struct)
  (export %DHT_BLOOM_SIZE
	  /:msg:dht:client:get:stop
	  /:msg:dht:client:get
	  /:msg:dht:client:get-result-known
	  /:msg:dht:client:result
	  /:msg:dht:client:put
	  /:msg:dht:monitor:put
	  /:msg:dht:monitor:start
	  /:msg:dht:monitor:stop
	  /:msg:dht:monitor:get
	  /:msg:dht:monitor:get-response)
  (import (only (rnrs base)
		define begin)
	  (only (gnu gnunet util struct)
		/:message-header /time-absolute)
	  (only (gnu gnunet hashcode struct)
		/hashcode:512)
	  (only (gnu gnunet netstruct syntactic)
		define-type structure/packed)
	  (only (gnu gnunet netstruct procedural)
		u32/big u64/big s16/big))
  (begin
    ;; Size of the bloom filter the DT uses to filter peers.
    (define %DHT_BLOOM_SIZE 128)

    (define-type /:msg:dht:client:get:stop
      (structure/packed
       (synopsis "Message indicating the DHT should cancel outstanding requests
and discard any state.")
       (field (header /:message-header)
	      (synopsis "Type: msg:dht:client:get:stop"))
       (field (reserved u32/big)
	      (synopsis "Always zero"))
       (field (reserved u64/big)
	      (synopsis "Unique ID identifying this request"))
       (field (key /hashcode:512)
	      (synopsis "Key of this request"))))

    ;; Possibly followed by xquery.
    (define-type /:msg:dht:client:get
      (structure/packed
       (synopsis "DHT GET message sent from clients to service, indicating a GET
request should be issued.")
       (field (header /:message-header)
	      (synopsis "Type: msg:dht:client:get"))
       (field (options u32/big)
	      (synopsis "Message options")) ; TODO enum
       (field (desired-replication-level u32/big)
	      (synopsis "Replication level for this message"))
       (field (type u32/big)
	      (synopsis "The type for the data for the GET request")) ; TODO enum
       (field (key /hashcode:512)
	      (synopsis "The key to search for"))
       (field (unique-id u64/big)
	      (synopsis "Unique ID identifying this request, if 0 then the client
will not expect a response"))))

    ;; Followed by an array of the hash codes of known results.
    (define-type /:msg:dht:client:get-result-known ;; XXX plural?
      (structure/packed
       (synopsis "Message sent from clients to service, indicating a GET request
should exclude certain results which are already known.")
       (field (header /:message-header)
	      (synopsis "Type: msg:dht:client:get-results-known"))
       (field (reserved u32/big)
	      (synopsis "Reserved, always 0"))
       (field (key /hashcode:512)
	      (synopsis "The key we are searching for (to make it easy to find the
corresponding GET inside the service)."))
       (field (unique-id u64/big)
	      (synopsis "Unique ID identifying this request"))))

    ;; put path, get path and actual data are copied to the end of this structure
    (define-type /:msg:dht:client:result
      (structure/packed
       (synopsis "Reply to a GET sent frrom the service to a client")
       (field (header /:message-header)
	      (synopsis "Type: msg:dht:client:result"))
       (field (type u32/big)
	      (synopsis "The type for the data"))
       (field (put-path-length u32/big)
	      (synopsis "Number of peers recorded in the outgoing path from
source to the storage location of this message"))
       (field (get-path-length u32/big)
	      (synopsis "The number of peer identities recorded from the storage
location to this peer."))
       (field (unique-id u64/big)
	      (synopsis "Unique ID of the matching GET request"))
       (field (expiration /time-absolute)
	      (synopsis "Expiration date of this entry"))
       (field (key /hashcode:512)
	      (synopsis "The key that was searched for"))))

    ;; Data is copied to the end of the message
    (define-type /:msg:dht:client:put
      (structure/packed
       (synopsis "Message to insert data into the DHT, sent from clients to DHT
service")
       (field (header /:message-header)
	      (synopsis "Type msg:dht:client:put"))
       (field (type u32/big)
	      (synopsis "The type of data to insert"))
       (field (option u32/big)
	      (synopsis "Message options")) ; TODO enum
       (field (desired-replication-level u32/big)
	      (synopsis "Replication level for this message"))
       (field (expiration /time-absolute)
	      (synopsis "Requested expiration data of this data"))
       (field (key /hashcode:512)
	      (synopsis "The key to store the value under"))))

    ;; Followed by put path (if tracked) and payload
    (define-type /:msg:dht:monitor:put
      (structure/packed
       (synopsis "Message to monitor put requests going through peer
(DHT service -> clients)")
       (field (header /:message-header)
	      (synopsis "Type: msg:dht:monitor:put"))
       (field (options u32/big)
	      (synopsis "Message options")) ; TODO enum
       (field (type u32/big)
	      (synopsis "The type of data in the request"))
       (field (hop-count u32/big)
	      (synopsis "Hop count so far"))
       (field (desired-replication-level u32/big)
	      (synopsis "Replication level for this message"))
       (field (put-path-length u32/big)
	      (synopsis "Number of peers recorded in the outgoing path from
source to the target location of this message."))
       (field (expiration-time /time-absolute)
	      (synopsis "How long the data should persist"))
       (field (key /hashcode:512)
	      (synopsis "The key to store the value under"))))

    (define-type /:msg:dht:monitor:start/stop
      (structure/packed
       ;; TODO: also to stop monitoring messages?
       (synopsis "Message to request monitoring messages, client -> DHT service")
       (field (header /:message-header)
	      (synopsis "Type: msg:dht:monitor:start or msg:dht:monitor:stop"))
       (field (type u32/big)
	      ;; XXX block types
	      (synopsis "The type of data desired, GNUNET_BLOCK_TYPE_ANY for all"))
       ;; FIXME: grammar
       (field (get? s16/big)
	      (synopsis "Flag whether to notify about GET messages"))
       (field (get-response? s16/big)
	      (synopsis "Flag whether to notify about GET_RESPONSE messages"))
       (field (put? s16/big)
	      (synopsis "Flag whether to notify about PUT messages"))
       (field (filter-key? s16/big)
	      (synopsis "Flag whether to use the provided key to filter messages"))
       (field (key /hashcode:512)
	      (synopsis "The key to filter messages by"))))

    (define-type /:msg:dht:monitor:start /:msg:dht:monitor:start/stop)
    (define-type /:msg:dht:monitor:stop /:msg:dht:monitor:start/stop)

    ;; Followed by get path (if tracked)
    (define-type /:msg:dht:monitor:get
      (structure/packed
       (synopsis "Message to monitor get requests going through peer,
DHT service -> clients.")
       (field (header /:message-header)
	      (synopsis "Type: msg:dht:monitor:get"))
       (field (options u32/big)
	      (synopsis "Message options")) ; TODO enum
       (field (type u32/big)
	      (synopsis "The type of data in the request"))
       (field (hop-count u32/big)
	      (synopsis "Hop count"))
       (field (desired-replication-level u32/big)
	      (synopsis "Replication level for this message"))
       (field (get-path-length u32/big)
	      (synopsis "Number of peers recorded in the outgoing path from
source to the storage location of this message"))
       (field (key /hashcode:512)
	      (synopsis "The key to store the value under"))))

    ;; followed by put path (if tracked), get path (if tracked) and payload
    (define-type /:msg:dht:monitor:get-response
      (structure/packed
       (synopsis "Message to monitor get requests going through peer,
DHT service -> clients")
       (field (header /:message-header)
	      ;; XXX correct?
	      (synopsis "Type: msg:dht:p2p:result"))
       (field (type u32/big)
	      (synopsis "Content type"))
       (field (put-path-length u32/big)
	      (synopsis "Length of the PUT path that follows (if tracked)"))
       (field (get-path-length u32/big)
	      (synopsis "Length of the GET path that follows (if tracked)"))
       (field (expiration-time /time-absolute)
	      (synopsis "When does the content expire?"))))))
